home *** CD-ROM | disk | FTP | other *** search
/ Aminet 38 / Aminet 38 (2000)(Schatztruhe)[!][Aug 2000].iso / Aminet / dev / misc / evaluate.lha / evaluate.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-19  |  23.1 KB  |  812 lines

  1. /* evaluate.c (C) 2000 Kyzer/CSG. */
  2. /* Released under the terms of the GNU General Public Licence version 2. */
  3.  
  4. #include "evaluate.h"
  5. #include <ctype.h>
  6. #include <limits.h>
  7. #include <math.h>
  8. #include <string.h>
  9.  
  10. /* a token structure */
  11. struct tok {
  12.   struct tok *next;
  13.   struct var *var;
  14.   struct val val;
  15.   char   token, funcid, *name, *name_end;
  16. };
  17.  
  18. /* token types */
  19. enum {
  20.   /* parentheses */
  21.   TK_OPEN, TK_CLOSE,
  22.  
  23.   /* variables and values */
  24.   TK_VAR, TK_VAL,
  25.  
  26.   /* binary operators */
  27.   TK_ADD, TK_SUB, TK_MUL, TK_MULI, TK_DIV,
  28.   TK_MOD, TK_POW, TK_AND, TK_OR, TK_BAND,
  29.   TK_BOR, TK_BXOR, TK_EQ, TK_NE, TK_LT, TK_GT,
  30.   TK_LE, TK_GE, TK_SHL, TK_SHR,
  31.  
  32.   /* unary operators */
  33.   TK_ASSN, TK_NEG, TK_FUNC, TK_NOT, TK_BNOT,
  34.  
  35.   /* special scan codes */
  36.   TK_BREAK, /* finish scanning, bring remainder of string forward */
  37.   TK_ERROR, /* abort scanning */
  38.   TK_SKIP   /* ignore the character */
  39. };
  40.  
  41. /* lookup table to do conversion [char -> token type] */
  42. char scantable[UCHAR_MAX+1];
  43. int scantable_ok = 0;
  44.  
  45. /* table of function names */
  46. char *functable[] = {
  47.   "acos", "asin", "atan", "cos", "cosh", "exp", "ln", "log",
  48.   "sin", "sinh", "sqr", "sqrt", "tan", "tanh", NULL
  49. };
  50.  
  51. /* function ids (index to functable) */
  52. enum {
  53.   F_ACOS, F_ASIN, F_ATAN, F_COS, F_COSH, F_EXP, F_LN, F_LOG,
  54.   F_SIN, F_SINH, F_SQR, F_SQRT, F_TAN, F_TANH
  55. };
  56.  
  57.  
  58.  
  59.  
  60. int same_str(const char *a, const char *b);
  61. int same_str_len(const char *a, const char *b, int len);
  62.  
  63. void init_scantable();
  64. int tokenize(struct memh *mh, char **string, struct tok **listptr);
  65. int scan_number(char **stringptr, struct val *valptr);
  66. int precedence(struct tok *t);
  67. int eval(struct memh *mh, struct tok *list, struct vartable *vt,
  68.   struct val *result);
  69.  
  70.  
  71. /*** FRONT-END ***/
  72.  
  73. int evaluate(char *expr, struct val *result, struct vartable *vartable) {
  74.   struct memh *mh = NULL;
  75.   int error = RESULT_OK, madevar = 0;
  76.   struct tok *list;
  77.   char *str;
  78.  
  79.   /* ensure we have a variable table */
  80.   if (!vartable) madevar = 1, vartable = create_vartable();
  81.   if (!vartable) return ERROR_NOMEM;
  82.  
  83.   init_scantable();
  84.  
  85.   if ((mh = create_mem())) {
  86.     if (expr && (str = (char *) mem_alloc(mh, strlen(expr)+1))) {
  87.       strcpy(str, expr);
  88.       while (*str) {
  89.     if ((error = tokenize(mh, &str, &list)) != RESULT_OK) break;
  90.     if ((error = eval(mh, list, vartable, result)) != RESULT_OK) break;
  91.       }
  92.     } else error = ERROR_NOMEM;
  93.   } else error = ERROR_NOMEM;
  94.  
  95.   free_mem(mh);
  96.   if (madevar) free_vartable(vartable);
  97.   return error;
  98. }
  99.  
  100.  
  101.  
  102.  
  103. /**** TOKENIZATION ***/
  104.  
  105. void init_scantable() {
  106.   int i;
  107.  
  108.   if (scantable_ok) return;
  109.  
  110.   for (i = 0; i <= UCHAR_MAX; i++)
  111.     scantable[i] =
  112.       isalpha(i) ? TK_VAR :
  113.      (isdigit(i) ? TK_VAL :
  114.      (isspace(i) ? TK_SKIP :
  115.                    TK_ERROR));
  116.  
  117.   scantable['+'] = TK_ADD;
  118.   scantable['-'] = TK_SUB;
  119.   scantable['*'] = TK_MUL;  /* also '**' = TK_POW */
  120.   scantable['/'] = TK_DIV;
  121.   scantable['%'] = TK_MOD;
  122.   scantable['$'] = TK_VAL;  /* '$' starts a hexadecimal value */
  123.   scantable['.'] = TK_VAL;  /* '.' starts a fractional value */
  124.   scantable['('] = TK_OPEN;
  125.   scantable[')'] = TK_CLOSE;
  126.   scantable[';'] = TK_BREAK;
  127.   scantable['='] = TK_ASSN; /* also '==' = TK_EQ */
  128.   scantable['~'] = TK_BNOT;
  129.   scantable['^'] = TK_BXOR;
  130.   scantable['&'] = TK_BAND; /* also '&&' = TK_AND */
  131.   scantable['|'] = TK_BOR;  /* also '||' = TK_OR */
  132.   scantable['!'] = TK_NOT;  /* also '!=' = TK_NE */
  133.   scantable['<'] = TK_LT;   /* also '<<' = TK_SHL, '<=' = TK_LE */
  134.   scantable['>'] = TK_GT;   /* also '>>' = TK_SHR, '>=' = TK_GE */
  135.  
  136.   scantable_ok = 1;
  137. }
  138.  
  139.  
  140. int tokenize(struct memh *mh, char **string, struct tok **listptr) {
  141.   struct tok *list;
  142.   int idx = 0, i, len;
  143.   char *s, *name, c, c2, nt;
  144.  
  145.   /* allocate a block of memory to hold the maximum amount of tokens */
  146.   i = strlen(*string) + 1;
  147.   list = (struct tok *) mem_alloc(mh, i * sizeof(struct tok));
  148.   if (!list) return ERROR_NOMEM;
  149.  
  150.   for (s = *string; *s; s++) {
  151.     /* get token type of character and store into list */
  152.     c = list[idx].token = scantable[* (unsigned char *) s];
  153.  
  154.     /* break out of the for loop on TK_BREAK */
  155.     if (c == TK_BREAK) { s++; break; }
  156.  
  157.     switch (c) {
  158.     case TK_ERROR:
  159.       return ERROR_SYNTAX;
  160.  
  161.     case TK_SKIP:
  162.       break;
  163.  
  164.     /* most symbol-tokens fall under this one - nothing much to do */
  165.     case TK_OPEN: case TK_CLOSE: case TK_ADD: case TK_SUB:
  166.     case TK_MUL: case TK_DIV: case TK_MOD: case TK_BAND: case TK_BOR:
  167.     case TK_BXOR: case TK_BNOT: case TK_NOT: case TK_LT: case TK_GT:
  168.  
  169.       /* check for 'double character' tokens */
  170.       c2 = s[1];
  171.       nt = 0;
  172.       if (c == TK_MUL  && c2 == '*') nt = TK_POW;
  173.       if (c == TK_BAND && c2 == '&') nt = TK_AND;
  174.       if (c == TK_BOR  && c2 == '|') nt = TK_OR;
  175.       if (c == TK_NOT  && c2 == '=') nt = TK_NE;
  176.       if (c == TK_LT   && c2 == '=') nt = TK_LE;
  177.       if (c == TK_LT   && c2 == '<') nt = TK_SHL;
  178.       if (c == TK_GT   && c2 == '=') nt = TK_GE;
  179.       if (c == TK_GT   && c2 == '>') nt = TK_SHR;
  180.       if (nt) { list[idx].token = nt; s++; }
  181.  
  182.       idx++;
  183.       break;
  184.  
  185.     case TK_ASSN:
  186.       /* '=' = TK_ASSN, '==' = TK_EQ */
  187.       if (s[1] == '=') { list[idx++].token = TK_EQ; s++; break; }
  188.  
  189.       /* if the last token was a variable, change it to an assignment */
  190.       if (idx <= 0 || list[idx-1].token != TK_VAR) return ERROR_SYNTAX;
  191.       list[idx-1].token = TK_ASSN;
  192.       break;
  193.  
  194.     case TK_VAL:
  195.       if (!scan_number(&s, &list[idx++].val)) return ERROR_SYNTAX;
  196.       s--; /* wind back one for the loop's iterator */
  197.       break;
  198.  
  199.     case TK_VAR:
  200.       list[idx].name = name = s;
  201.       while (scantable[s[1]] == TK_VAR) s++; /* skip to end of string */
  202.       list[idx].name_end = s+1;
  203.       len = s+1 - name;
  204.  
  205.       /* look for matching function */
  206.       for (i = 0; functable[i]; i++) {
  207.         char *fname = functable[i];
  208.         if (same_str_len(name, fname, len) && strlen(fname) == len) {
  209.           list[idx].token  = TK_FUNC;
  210.           list[idx].funcid = i;
  211.           break;
  212.         }
  213.       }
  214.       idx++;
  215.       break;
  216.     }
  217.   }
  218.  
  219.   /* write back the final position of the tokenizer - either pointing at
  220.    * a null character, or the next expression to go */
  221.   *string = s;
  222.  
  223.   /* lace up the tokens and null-terminate the strings */
  224.   if (idx > 0) {
  225.     for (i = 0; i < idx; i++) {
  226.       list[i].next = &list[i+1];
  227.       if (list[i].token == TK_VAR || list[i].token == TK_ASSN)
  228.         *(list[i].name_end) = '\0';
  229.     }
  230.     list[idx-1].next = NULL;
  231.     *listptr = list;
  232.   }
  233.   else {
  234.     *listptr = NULL;
  235.   }
  236.  
  237.   return RESULT_OK;
  238. }
  239.  
  240.  
  241. /* scans some text into a value */
  242. int scan_number(char **stringptr, struct val *valptr) {
  243.   struct val v = { T_INT, 0, 0.0 };
  244.   char *s = *stringptr;
  245.   int c;
  246.   double dp;
  247.  
  248.   /* test to see if it's a hex number */
  249.   if (s[0] == '$' || (s[0] == '0' && s[1] == 'x')) {
  250.     s += (s[1] == 'x') ? 2 : 1;
  251.     *stringptr = s;
  252.  
  253.     for (; isxdigit(c = (int) *s); s++)
  254.       v.ival = (v.ival << 4)
  255.         + (isdigit(c) ? c-'0'      : 0)
  256.         + (isupper(c) ? c-'A' + 10 : 0)
  257.         + (islower(c) ? c-'a' + 10 : 0);
  258.   }
  259.  
  260.   /* must be a decimal integer or real */
  261.   else {
  262.     for (; isdigit(c = (int) *s); s++) v.ival = (v.ival * 10) + c-'0';
  263.     if (*s == '.') {
  264.       *stringptr = ++s;
  265.       v.type = T_REAL;
  266.       v.rval = (double) v.ival;
  267.       for (dp = 0.1; isdigit(c = (int) *s); s++, dp /= 10.0)
  268.         v.rval += dp * (double) (c-'0');
  269.     }
  270.   }
  271.  
  272.   /* if no numeric chars have been read, it's a dud - return FAIL */
  273.   if (s == *stringptr) return 0;
  274.  
  275.   /* otherwise, update position and return SUCCESS */
  276.   *stringptr = s;
  277.   *valptr = v;
  278.   return 1;
  279. }
  280.  
  281.  
  282. /*** EVALUATION ***/
  283.  
  284. /* returns the precedence of a token */
  285. int precedence(struct tok *t) {
  286.   switch (t->token) {
  287.   case TK_MULI:                            return 14;
  288.   case TK_NEG:    case TK_NOT:    case TK_BNOT:            return 13;
  289.   case TK_POW:                            return 12;
  290.   case TK_MUL:    case TK_DIV:    case TK_MOD:            return 11;
  291.   case TK_ADD:    case TK_SUB:                    return 10;
  292.   case TK_SHL:    case TK_SHR:                    return 9;
  293.   case TK_LT:    case TK_GT:    case TK_LE:    case TK_GE:    return 8;
  294.   case TK_EQ:    case TK_NE:                    return 7;
  295.   case TK_BAND:                            return 6;
  296.   case TK_BOR:    case TK_BXOR:                    return 5;
  297.   case TK_AND:    case TK_OR:                    return 4;
  298.   case TK_ASSN:                            return 3;
  299.   case TK_FUNC:                            return 2;
  300.   case TK_OPEN:    case TK_CLOSE:                    return 1;
  301.   }
  302.   return 0;
  303. }
  304.  
  305.  
  306. int eval(struct memh *mh, struct tok *list, struct vartable *vt,
  307.   struct val *result) {
  308.  
  309.   struct val newval = { T_INT, 0, 0.0 }, env, *valstk, *x, *y;
  310.   struct tok open, close, *l, *r, *t, **opstk;
  311.   char *envtxt, lt, rt, token;
  312.   int vstk, ostk, vcnt = 0, ocnt = 0, error;
  313.   double xr, yr, rr = 0;
  314.   long xi, yi, ri = 0;
  315.  
  316.   /* clear result before we do anything - and no tokens is no result */
  317.   *result = newval;
  318.   if (!list) return RESULT_OK;
  319.  
  320.  
  321.   /* CONVERSION OF RAW TOKENS INTO COMPLETE INFIX EXPRESSION */
  322.  
  323.   /* wrap the token list in a pair of parentheses */
  324.   for (t = list; t->next; t = t->next); t->next = &close;
  325.   close.next = NULL; open.next = list; list = &open;
  326.   close.token = TK_CLOSE; open.token  = TK_OPEN;
  327.  
  328.   /* insert and change tokens as neccessary */
  329.   for (l=list, r=l->next; r->next; l=r, r=r->next) {
  330.     lt = l->token;
  331.     rt = r->token;
  332.  
  333.     /* convert TK_SUBs that should be unary into TK_NEGs */
  334.     if (rt == TK_SUB && lt != TK_CLOSE && lt != TK_VAR && lt != TK_VAL)
  335.       r->token = TK_NEG;
  336.  
  337.     /* insert implicit multiplication tokens */
  338.     if ((lt == TK_VAR || lt == TK_VAL || lt == TK_CLOSE)
  339.     && (rt == TK_VAR || rt == TK_VAL || rt == TK_OPEN || rt == TK_FUNC)) {
  340.       if (lt == rt) return ERROR_SYNTAX;
  341.       t = (struct tok *) mem_alloc(mh, sizeof(struct tok));
  342.       if (!t) return ERROR_NOMEM;
  343.       t->token = TK_MULI; l->next = t; t->next = r;
  344.     }
  345.   }
  346.  
  347.   /* VARIABLE CHECKING */
  348.  
  349.   vcnt = ocnt = 0;
  350.   for (t = list; t; t = t->next) {
  351.     lt = t->token;
  352.  
  353.     /* count the number of values and operators */
  354.     if (lt == TK_VAR || lt == TK_VAL) vcnt++; else ocnt++;
  355.  
  356.     /* if assigned variables don't exist, create a new blank one */
  357.     if (lt == TK_ASSN) {
  358.       if (!(t->var = get_var(vt, t->name)))
  359.         if (!(t->var = put_var(vt, t->name, &newval)))
  360.           return ERROR_NOMEM;
  361.     }
  362.  
  363.     /* try to get vars from vartable - if not, try the environment */
  364.     else if (lt == TK_VAR) {
  365.       if (!(t->var = get_var(vt, t->name))) {
  366.         if (!(envtxt = getenv(t->name))) return ERROR_VARNOTFOUND;
  367.         if (!scan_number(&envtxt, &env)) return ERROR_SYNTAX;
  368.         if (!(t->var = put_var(vt, t->name, &env))) return ERROR_NOMEM;
  369.       }
  370.     }
  371.   }
  372.  
  373.   /* ALLOCATE STACKS */
  374.  
  375.   /* allocate the operator stack and the value stack */
  376.   valstk = (struct val *)  mem_alloc(mh, vcnt * sizeof(struct val));
  377.   opstk  = (struct tok **) mem_alloc(mh, ocnt * sizeof(struct tok *));
  378.   if (!valstk || !opstk) return ERROR_NOMEM;
  379.  
  380.   /* set the stack pointers to '0 items on stack' */
  381.   /* (the stack pointers are always set at the topmost stack item) */
  382.   ostk = vstk = -1;
  383.  
  384.   /* MAIN EVALUATION LOOP */
  385.  
  386.   for (t = list; t; t=t->next) {
  387.     switch (t->token) {
  388.  
  389.     /* unary operators always wait until after what follows is evaluated */
  390.     /* also, open parentheses are pushed to match where close ones stop */
  391.     case TK_OPEN:
  392.     case TK_ASSN: case TK_NEG: case TK_FUNC: case TK_NOT: case TK_BNOT:
  393.       opstk[++ostk] = t; break;
  394.  
  395.     /* values go straight on the value stack */
  396.     case TK_VAL:
  397.       valstk[++vstk] = t->val;
  398.       break;
  399.  
  400.     /* variables go straight on the value stack */
  401.     case TK_VAR:
  402.       valstk[++vstk] = t->var->val;
  403.       break;
  404.  
  405.     /* this is where the action happens - all operations of a higher
  406.      * precedence are now executed. then, after that, we push the operator
  407.      * to the stack, or if it's a close paren, pull and expect an open paren
  408.      *
  409.      * it's assumed that all tokens in the token stream that aren't one of
  410.      * the previous cases must be the close bracket or a binary operator -
  411.      * that's why 'default' is used rather than all the names
  412.      */
  413.     default:
  414.       while (precedence(opstk[ostk]) > precedence(t)) {
  415.         struct tok *op = opstk[ostk--];
  416.  
  417.         /* there should always be at least a close bracket left here */
  418.         if (ostk < 0) return ERROR_SYNTAX;
  419.  
  420.         /* we assume that all operators require at least one value */
  421.         /* on the stack, and check here */
  422.         if (vstk < 0) return ERROR_SYNTAX;
  423.  
  424.         /* now we actually perform evaluations */
  425.         switch (token = op->token) {
  426.  
  427.         /* binary (int/real) -> (int/real) */
  428.         case TK_ADD: case TK_SUB: case TK_MUL: case TK_MULI:
  429.  
  430.           /* pull two values from the stack, y then x, and push 'x op y' */
  431.           if (vstk < 1) return ERROR_SYNTAX;
  432.           y = &valstk[vstk--]; x = &valstk[vstk];
  433.  
  434.           /* if both values are integer, do integer operations only */
  435.           if (x->type == T_INT && y->type == T_INT) {
  436.             xi = x->ival;
  437.             yi = y->ival;
  438.             switch (token) {
  439.             case TK_MULI:
  440.             case TK_MUL: ri = (xi * yi); break;
  441.             case TK_ADD: ri = (xi + yi); break;
  442.             case TK_SUB: ri = (xi - yi); break;
  443.             }
  444.             /* push int-value result to value stack */
  445.             x->type = T_INT;
  446.             x->ival = ri;
  447.           }
  448.           else {
  449.             /* get real values - convert if neccessary */
  450.             xr = (x->type == T_REAL) ? x->rval : (double) x->ival;
  451.             yr = (y->type == T_REAL) ? y->rval : (double) y->ival;
  452.  
  453.             switch (token) {
  454.             case TK_MULI:
  455.             case TK_MUL: rr = (xr * yr); break;
  456.             case TK_ADD: rr = (xr + yr); break;
  457.             case TK_SUB: rr = (xr - yr); break;
  458.             }
  459.             /* push real-value result to value stack */
  460.             x->type = T_REAL;
  461.             x->rval = rr;
  462.           }
  463.           break;
  464.  
  465.  
  466.  
  467.         /* binary (int/real) -> int */
  468.         case TK_EQ: case TK_NE: case TK_LT:
  469.         case TK_GT: case TK_LE: case TK_GE:
  470.  
  471.           if (vstk < 1) return ERROR_SYNTAX;
  472.           y = &valstk[vstk--]; x = &valstk[vstk];
  473.  
  474.           if (x->type == T_INT && y->type == T_INT) {
  475.             xi = x->ival;
  476.             yi = y->ival;
  477.             switch (token) {
  478.             case TK_EQ:  ri = (xi == yi); break;
  479.             case TK_NE:  ri = (xi != yi); break;
  480.             case TK_LT:  ri = (xi <  yi); break;
  481.             case TK_GT:  ri = (xi >  yi); break;
  482.             case TK_LE:  ri = (xi <= yi); break;
  483.             case TK_GE:  ri = (xi >= yi); break;
  484.             }
  485.           }
  486.           else {
  487.             xr = (x->type == T_REAL) ? x->rval : (double) x->ival;
  488.             yr = (y->type == T_REAL) ? y->rval : (double) y->ival;
  489.             switch (token) {
  490.             case TK_EQ:  ri = (xr == yr); break;
  491.             case TK_NE:  ri = (xr != yr); break;
  492.             case TK_LT:  ri = (xr <  yr); break;
  493.             case TK_GT:  ri = (xr >  yr); break;
  494.             case TK_LE:  ri = (xr <= yr); break;
  495.             case TK_GE:  ri = (xr >= yr); break;
  496.             }
  497.           }
  498.           x->type = T_INT;
  499.           x->ival = ri;
  500.           break;
  501.  
  502.  
  503.         /* binary real -> real */
  504.         case TK_DIV: case TK_POW:
  505.  
  506.           if (vstk < 1) return ERROR_SYNTAX;
  507.           y = &valstk[vstk--]; x = &valstk[vstk];
  508.           xr = (x->type == T_REAL) ? x->rval : (double) x->ival;
  509.           yr = (y->type == T_REAL) ? y->rval : (double) y->ival;
  510.  
  511.           if (token == TK_DIV) {
  512.             if (yr == 0) return ERROR_DIV0;
  513.             x->rval = xr / yr;
  514.           }
  515.           else {
  516.             x->rval = pow(xr, yr);
  517.           }
  518.           x->type = T_REAL;
  519.       break;
  520.  
  521.  
  522.         /* binary int -> int */
  523.         case TK_MOD: case TK_AND: case TK_OR:
  524.         case TK_BAND: case TK_BOR: case TK_BXOR:
  525.         case TK_SHL: case TK_SHR:
  526.  
  527.           if (vstk < 1) return ERROR_SYNTAX;
  528.           y = &valstk[vstk--]; x = &valstk[vstk];
  529.           xi = (x->type == T_INT) ? x->ival : (long) x->rval;
  530.           yi = (y->type == T_INT) ? y->ival : (long) y->rval;
  531.  
  532.           switch (token) {
  533.           case TK_MOD:  if (yi == 0) return ERROR_DIV0;
  534.                         ri = (xi %  yi); break;
  535.           case TK_AND:  ri = (xi && yi); break;
  536.           case TK_OR:   ri = (xi || yi); break;
  537.           case TK_BAND: ri = (xi &  yi); break;
  538.           case TK_BOR:  ri = (xi |  yi); break;
  539.           case TK_BXOR: ri = (xi ^  yi); break;
  540.           case TK_SHL:  ri = (xi << yi); break;
  541.           case TK_SHR:  ri = (xi >> yi); break;
  542.           }
  543.  
  544.           x->type = T_INT;
  545.           x->ival = ri;
  546.           break;
  547.  
  548.  
  549.  
  550.         /* unary real -> real */
  551.         case TK_FUNC:
  552.           x = &valstk[vstk];
  553.           xr = (x->type == T_REAL) ? x->rval : (double) x->ival;
  554.           switch (op->funcid) {
  555.           case F_ACOS: xr =  acos(xr); break;
  556.           case F_ASIN: xr =  asin(xr); break;
  557.           case F_ATAN: xr =  atan(xr); break;
  558.           case F_COS:  xr =   cos(xr); break;
  559.           case F_COSH: xr =  cosh(xr); break;
  560.           case F_EXP:  xr =   exp(xr); break;
  561.           case F_LN:   xr =   log(xr); break;
  562.           case F_LOG:  xr = log10(xr); break;
  563.           case F_SIN:  xr =   sin(xr); break;
  564.           case F_SINH: xr =  sinh(xr); break;
  565.           case F_SQR:  xr =   xr * xr; break;
  566.           case F_SQRT: xr =  sqrt(xr); break;
  567.           case F_TAN:  xr =   tan(xr); break;
  568.           case F_TANH: xr =  tanh(xr); break;
  569.           }
  570.           x->rval = xr;
  571.           x->type = T_REAL;
  572.           break;
  573.  
  574.  
  575.         /* unary int -> int */
  576.         case TK_BNOT: case TK_NOT:
  577.  
  578.           x = &valstk[vstk];
  579.           xi = (x->type == T_INT) ? x->ival : (long) x->rval;
  580.           if (token == TK_BNOT) {
  581.             x->ival = ~ xi;
  582.           }
  583.           else {
  584.             x->ival = ! xi;
  585.           }
  586.           x->type = T_INT;
  587.           break;
  588.  
  589.  
  590.         /* unary (int/real) -> (int/real) */
  591.         case TK_ASSN:
  592.           op->var->val = valstk[vstk];
  593.           break;
  594.  
  595.  
  596.         /* unary (int/real) -> (int/real) */
  597.         case TK_NEG:
  598.           x = &valstk[vstk];
  599.           if (x->type == T_INT)
  600.             x->ival = - x->ival;
  601.           else
  602.             x->rval = - x->rval;
  603.           break;
  604.  
  605.         } /* end select (execution switch) */
  606.       } /* end while (precedence loop) */
  607.  
  608.       /* back to the postfixified */
  609.  
  610.       /* if we had a close paren, pull the matching open paren (error if
  611.        * we pull something else. otherwise push our new operator
  612.        */
  613.       if (t->token == TK_CLOSE) {
  614.         if (opstk[ostk--]->token != TK_OPEN) return ERROR_SYNTAX;
  615.       }
  616.       else {
  617.         opstk[++ostk] = t;
  618.       }
  619.     }
  620.   }
  621.  
  622.   /* there should be exactly one value and no operators left on the stacks */
  623.   if (vstk != 0 || ostk != -1) return ERROR_SYNTAX;
  624.  
  625.   /* return that value */
  626.   *result = valstk[0];
  627.   return RESULT_OK;
  628. }
  629.  
  630.  
  631.  
  632.  
  633.  
  634. /** debugging things **/
  635. #if 0
  636. /* expression printer */
  637. void prt(struct tok *t) {
  638.   for (; t; t=t->next) {
  639.     switch(t->token)  {
  640.     case TK_OPEN:  printf("( ");  break;
  641.     case TK_CLOSE: printf(") ");  break;
  642.  
  643.     case TK_ADD:   printf("+ ");  break;
  644.     case TK_SUB:   printf("- ");  break;
  645.     case TK_MUL:   printf("* ");  break;
  646.     case TK_MULI:  printf("*i "); break;
  647.     case TK_POW:   printf("** "); break;
  648.     case TK_DIV:   printf("/ ");  break;
  649.     case TK_MOD:   printf("%% "); break;
  650.  
  651.     case TK_EQ:    printf("== "); break;
  652.     case TK_NE:    printf("!= "); break;
  653.     case TK_LT:    printf("< ");  break;
  654.     case TK_GT:    printf("> ");  break;
  655.     case TK_LE:    printf("<= "); break;
  656.     case TK_GE:    printf(">= "); break;
  657.  
  658.     case TK_AND:   printf("&& "); break;
  659.     case TK_BAND:  printf("& ");  break;
  660.     case TK_BNOT:  printf("~ ");  break;
  661.     case TK_BOR:   printf("| ");  break;
  662.     case TK_BXOR:  printf("^ ");  break;
  663.     case TK_NEG:   printf("_ ");  break;
  664.     case TK_NOT:   printf("! ");  break;
  665.     case TK_OR:    printf("|| "); break;
  666.     case TK_SHL:   printf("<< "); break;
  667.     case TK_SHR:   printf(">> "); break;
  668.  
  669.     case TK_ASSN:  printf("%s = ", t->name); break;
  670.     case TK_FUNC:  printf("%s ", functable[t->funcid]); break;
  671.     case TK_VAL:   if (t->val.type == T_INT)
  672.                      printf("%ld ", t->val.ival);
  673.                    else
  674.                      printf("%g ", t->val.rval);
  675.                    break;
  676.  
  677.     case TK_VAR:   printf("%s ", t->name); break;
  678.     default:       printf("??(%d)", t->token); break;
  679.     }
  680.   }
  681.   printf("\n");
  682. }
  683.  
  684. /* variables dumper */
  685. void dump_vars(struct vartable *vt) {
  686.   struct var *v;
  687.   if (!vt) printf("no vars\n");
  688.   else for (v=vt->first; v; v=v->next) {
  689.     if (v->val.type == T_INT)
  690.       printf("'%s'=%ld ", v->name, v->val.ival);
  691.     else
  692.       printf("'%s'=%g ", v->name, v->val.rval);
  693.   }
  694.   printf("\n");
  695. }
  696. #endif
  697.  
  698.  
  699.  
  700. /*** UTILITY FUNCTIONS ***/
  701.  
  702. /* case-insensitive string comparison, TRUE or FALSE result */
  703. int same_str(const char *a, const char *b) {
  704.   if (!a || !b) return 0; /* false even if a == b == null */
  705.   if (a == b) return 1;
  706.  
  707. #ifdef HAVE_STRCASECMP
  708.   return (strcasecmp(a, b) == 0);
  709. #elif HAVE_STRCMPI
  710.   return (strcmpi(a, b) == 0);
  711. #else
  712.   while ((tolower((int)*a) == tolower((int)*b))) {
  713.     if (!*a) return 1; /* if end of both strings, return true */
  714.     a++; b++;
  715.   }
  716.   return 0; /* mismatch before end of string - return false */
  717. #endif
  718. }
  719.  
  720. /* case-insensitive string comparison with maximum length */
  721. int same_str_len(const char *a, const char *b, int len) {
  722.   if (!a || !b) return 0; /* false even if a == b == null */
  723.   if (len == 0) return 0;
  724.   if (a == b) return 1;
  725.  
  726. #ifdef HAVE_STRNCASECMP
  727.   return (strncasecmp(a, b, len) == 0);
  728. #elif HAVE_STRNCMPI
  729.   return (strncmpi(a, b) == 0);
  730. #else
  731.   while (--len && (tolower((int)*a) == tolower((int)*b))) {
  732.     if (!*a) return 1; /* true if both strings equal & end before len */
  733.     a++; b++;
  734.   }
  735.   /* result based on last char of allowed length */
  736.   return (tolower((int)*a) == tolower((int)*b)) ? 1 : 0;
  737. #endif
  738. }
  739.  
  740. /* tracked memory allocation - create header */
  741. struct memh *create_mem() {
  742.   struct memh *mh = (struct memh *) malloc(sizeof(struct memh));
  743.   mh->next = NULL;
  744.   mh->ptr  = NULL;
  745.   return mh;
  746. }
  747.  
  748. /* tracked memory allocation - allocate memory using header */
  749. void *mem_alloc(struct memh *mh, size_t len) {
  750.   struct memh *mem = (struct memh *) malloc(len + sizeof(struct memh));
  751.   if (!mem) return NULL;
  752.   mem->next = mh->next;
  753.   mh->next = mem;
  754.   return mem->ptr = (void *) &mem[1];
  755. }
  756.  
  757. /* tracked memory allocation - free all memory in header */
  758. void free_mem(struct memh *mh) {
  759.   struct memh *next;
  760.   for (; mh; mh = next) {
  761.     next = mh->next;
  762.     free(mh);
  763.   }
  764. }
  765.     
  766. /* creates an empty variable table */
  767. struct vartable *create_vartable() {
  768.   struct memh *mh = create_mem();
  769.   struct vartable *vt;
  770.   vt = (struct vartable *) mem_alloc(mh, sizeof(struct vartable));
  771.   if (mh && vt) vt->mh = mh, vt->first = NULL; else free_mem(mh);
  772.   return vt;
  773. }
  774.  
  775. /* frees a variable table */
  776. void free_vartable(struct vartable *vt) {
  777.   free_mem(vt->mh);
  778. }
  779.  
  780. /* gets a variable out of a variable table */
  781. struct var *get_var(struct vartable *vt, char *name) {
  782.   struct var *v;
  783.   if (!vt || !name) return NULL;
  784.   for (v = vt->first; v; v = v->next) if (same_str(v->name, name)) return v;
  785.   return NULL;
  786. }
  787.  
  788. /* creates a new variable in a variable table */
  789. struct var *put_var(struct vartable *vt, char *name, struct val *value) {
  790.   struct var *v;
  791.   char *n;
  792.  
  793.   if (!vt || !name || !value) return NULL;
  794.  
  795.   if ((v = get_var(vt, name))) {
  796.     v->val = *value;
  797.     return v;
  798.   }
  799.  
  800.   v = (struct var *) mem_alloc(vt->mh, sizeof(struct var));
  801.   n = (char *) mem_alloc(vt->mh, strlen(name)+1);
  802.   if (v && n) {
  803.     strcpy(n, name);
  804.     v->name = n;
  805.     v->val  = *value;
  806.     v->next = vt->first;
  807.     vt->first = v;
  808.     return v;
  809.   }
  810.   return NULL;
  811. }
  812.